package com.zbmy.plugin.im.server.core.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.ReferenceCountUtil;

import java.util.List;

import com.zbmy.plugin.im.server.core.protocol.MessageHolder;
import com.zbmy.plugin.im.server.core.protocol.ProtocolHeader;


/**
 * 解码Handler.
 *
 *                                       Jelly Protocol
 *  __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
 * |           |           |           |           |              |                          |
 *       2           1           1           1            4               Uncertainty
 * |__ __ __ __|__ __ __ __|__ __ __ __|__ __ __ __|__ __ __ __ __|__ __ __ __ __ __ __ __ __|
 * |           |           |           |           |              |                          |
 *     Magic        Sign        Type       Status     Body Length         Body Content
 * |__ __ __ __|__ __ __ __|__ __ __ __|__ __ __ __|__ __ __ __ __|__ __ __ __ __ __ __ __ __|
 *
 * 协议头9个字节定长
 *     Magic      // 数据包的验证位，short类型
 *     Sign       // 消息标志，请求／响应／通知，byte类型
 *     Type       // 消息类型，登录／发送消息等，byte类型
 *     Status     // 响应状态，成功／失败，byte类型
 *     BodyLength // 协议体长度，int类型
 *
 * 已经做了粘包处理
 * @author Yangleping.
 */
public class ProtocolDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int nReadableBytes = in.readableBytes();
    	if (nReadableBytes < ProtocolHeader.HEADER_LENGTH) {	// 数据包的长度必须大于等于我们自定义一个包的协议的长度，处理毡包
            // 数据包长度小于协议头长度
            //logger.info("数据包长度小于协议头长度");
            return;
        }
        in.markReaderIndex();	// 标志下当前所处的reader index
        //int beginIndex =  in.readerIndex();
        short magic = in.readShort();
        if (magic != ProtocolHeader.MAGIC) {  // 数据包的验证位，必须为0xabcd 2位
            // Magic不一致，表明不是自己的数据
            //logger.info("Magic不一致");
            in.resetReaderIndex();			// 因为处理出现异常，需要回到原来完整得包位置，表示没读过。下次进来还是一样得
            return;
        }
        // 开始解码
        byte sign = in.readByte();		// 读取下一个字节，消息标志，请求／响应／通知，byte类型
        byte type = in.readByte();		// 读取下一个字节，消息类型，登录／发送消息等，byte类型
        byte status = in.readByte();	// 响应状态，成功／失败，byte类型
        // 确认消息体长度
        int bodyLength = in.readInt();	// 4个字节消息长度
        nReadableBytes = in.readableBytes();
        if (nReadableBytes < bodyLength) {
            // 消息体长度不一致
            //logger.info("消息体长度不一致");
            in.resetReaderIndex();
            return;
        }
        
        // 测试
        /*in.resetReaderIndex();
        in.readerIndex(beginIndex + 9 + bodyLength);
        ByteBuf otherByteBufRef = in.slice(beginIndex, 9 + bodyLength);
        otherByteBufRef.retain();
        */
        byte[] bytes = new byte[bodyLength];
        in.readBytes(bytes);
        //otherByteBufRef.readBytes(bytes);
        
        
        MessageHolder messageHolder = new MessageHolder();
        messageHolder.setSign(sign);
        messageHolder.setType(type);
        messageHolder.setStatus(status);
        messageHolder.setBody(new String(bytes, "utf-8"));
        out.add(messageHolder);
    }
    
    /**
     * int 类型占32个字节； 4 位；
short 类型占16个字节； 2位；
long 类型占64个字节； 8位；
float 类型占32个字节； 4位；
double 类型占64个字节； 8位；
char 类型占16个字节； 2位；
boolean类型占8个字节； 1位；

byte 类型占8个字节； 1位；
     */
}
